package com.cuke.entityhelper.actions.chainMethod.entityHelper.base;

import com.cuke.entityhelper.actions.chainMethod.entityHelper.dialog.GenerateDialog;
import com.cuke.entityhelper.actions.chainMethod.entityHelper.dialog.MethodGenerator;
import com.cuke.entityhelper.enums.ChainMethodType;
import com.cuke.entityhelper.utils.PsiElementUtils;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.cuke.entityhelper.utils.PsiClassUtils;
import com.intellij.psi.PsiLocalVariable;
import com.intellij.psi.util.PsiTreeUtil;
import org.apache.commons.collections.CollectionUtils;
import org.jetbrains.annotations.NotNull;

import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 针对实体类的，链式赋值方法生成器
 */
public abstract class BaseGenerateChainMethod extends AnAction {

    protected abstract ChainMethodType getChainMethodType();

    @Override
    public void actionPerformed(AnActionEvent e) {

        try {
            //因为Intellij Platform不允许在主线程中进行实时的文件写入，而需要通过一个异步任务来进行
            WriteCommandAction.runWriteCommandAction(e.getProject(), () -> {

                PsiClass psiClass = PsiElementUtils.getPsiClassFromCursor(e);
                if (psiClass == null) {
                    return;
                }

                GenerateDialog dlg = new GenerateDialog(psiClass);
                if (dlg.showAndGet()) {

                    Set<String> fieldNames = dlg.getFields().stream().map(x -> x.getName()).collect(Collectors.toSet());
                    if (CollectionUtils.isEmpty(fieldNames)) {
                        return;
                    }

                    ChainMethodType chainMethodType = getChainMethodType();
                    switch (chainMethodType) {
                        case with: {
                            //删除已存在的方法
                            Arrays.stream(psiClass.getMethods()).filter(psiMethod -> psiMethod.getName().startsWith("with")).forEach(psiMethod -> psiMethod.delete());
                            MethodGenerator.genWithMethod(psiClass, dlg.getFields());
                            break;
                        }
                        case build: {
                            //删除已存在的方法
                            Arrays.stream(psiClass.getMethods()).filter(psiMethod -> fieldNames.contains(psiMethod.getName())).forEach(psiMethod -> psiMethod.delete());
                            MethodGenerator.genBuilderMethod(psiClass, dlg.getFields());
                        }
                    }

                }
            });
        } catch (Throwable e1) {
            //e1.printStackTrace();
            System.out.println(e1.getMessage());
        }
    }

    /**
     * 根据用户光标位置，用户操作上下文，环境等情况，判断要不要显示代码生成操作点击入口
     * 如，根据对象声明的变量名，生成这个对象的所有 set 方法，并赋默认值， 要求的前提是用户点击了这个变量名
     * 如，生成 entity中的链式 set方法，要求，当前打开(光标所在)的类是一个实体类，即，至少要有一个属性
     * 等等
     *
     * @param e
     */
    @Override
    public void update(@NotNull AnActionEvent e) {
        e.getPresentation().setVisible(isAvailable(e));
    }

    private Boolean isAvailable(AnActionEvent e) {
        Editor editor = e.getData(PlatformDataKeys.EDITOR);
        PsiFile file = e.getData(PlatformDataKeys.PSI_FILE);
        if (editor == null || file == null) {
            return false;
        }
        PsiClass psiClass = PsiClassUtils.getPsiClassFromContext(e);
        if (null == psiClass) {
            return false;
        }
        long fieldCount = Arrays.stream(psiClass.getAllFields()).filter(field -> !"serialVersionUID".equalsIgnoreCase(field.getName())).count();
        if (fieldCount == 0) {
            return false;
        }
        return true;
    }
}
